# listener.py - Jukee
#
# Copyright (C) 2008 Ruben Medellin <ruben.medellin.c@gmail.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the
#    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
#    Boston, MA  02111-1307  USA

"""
This module contains the client's listener for server events (changes
in the playlist, votes, etc.)
"""

import Pyro.naming
from Pyro.EventService.Clients import Subscriber
from Pyro.errors import *
from threading import Thread
from socket import gethostname
from jukee.common.clientmodel import ClientModel
from jukee.libs.Observable import Observable
from jukee.utils.utils import debug, warn, error
import sys

#################### Event listener ####################

class EventListener(Thread, Observable):
  """Runs a Pyro event listener and connects it to the server"""

  def __init__(self):
    """
    At creation time, the Event Listener will try to get an instance of the Jukebox
    remote object, and obtain the configuration from there.
    """
    # Initialize daemon
    Pyro.config.PYRO_NS_HOSTNAME = "192.168.1.145"
    warn("PYRO_NS_HOSTNAME Hardcoded into " + str(Pyro.config.PYRO_NS_HOSTNAME))

    debug("Initializing EventListener")
    Thread.__init__(self)
    Observable.__init__(self)
    self.setDaemon(True)

    # Get reference of the Name Server, if found
    # FIXME: Catch exceptions
    Pyro.core.initClient()
    locator = Pyro.naming.NameServerLocator()
    warn("Automatic recognition of the remote object not implemented")
    _myobj = raw_input("Name of the remote object: ") #FIXME This should be automatic? Options?
    ns = locator.getNS()
    uri = ns.resolve(_myobj)

    # Get the remote object
    self.jukebox_instance = Pyro.core.getProxyForURI(uri)

    # TODO: Connection Logic here
    self.client_id = self.connect()
    self.remote_config = self.get_remote_config()

  def run(self):
    """
    Starts the Event Listener in the background, and subscribes it to the
    events fired by the previously grabbed (at initialization) remote jukebox 
    """
    self.listener = PlaylistView(self)

    DEFAULT_JUKEBOX_NAME = "jukee"
    name = str(self.remote_config.get("name", DEFAULT_JUKEBOX_NAME))
    
    ## FIXME: Build regexp properly
    subscribe_regexp = "^JUKEE\." + name + "\\..*$"
    try:
      self.listener.subscribeMatch(subscribe_regexp)
      debug("Event Listener subscribed to " + subscribe_regexp)

      debug("Event Listener activated")
      self.listener.listen()
    except Exception, e:
      error(e)
      raise e

  def connect(self):
    name = raw_input("Your name: ")  # TODO: Add name on connection
    client_model = ClientModel(
      {
        'name':name,
        'hostname':gethostname()
      })
    response = self.jukebox_instance.connect(client_model)
    
    if not response:
      warn("Server didn't answer")
      sys.exit("Couldn't find server")
    else:
      debug("Server responded with client id: " + str(response))
      return response

  def get_remote_config(self):
    remote_config = self.jukebox_instance.get_config_params()
    debug("Server has the following remote configuration: " + str(remote_config))
    return remote_config

#################### The suscriber client ####################

class PlaylistView(Subscriber):
  """Will receive notifications about changes, and handle them"""

  def __init__(self, event_listener):
    Subscriber.__init__(self)
    self.event_listener = event_listener
    debug("Playlist View created")
    
  def event(self, event):
    warn("Event handler not implemented")
    debug("Event: " + str(event.subject) + ", Subject: " + str(event.msg))
    self.event_listener.broadcastEvent(event.subject, event.msg)
